// File:       piscmd01.c++
// Version:    1.00
// Author:     (c) Miles Sabin, 1997
// Purpose:    integral type extraction command

// Change log:
//  27/03/97   v. 1.00

#include "piscmds.h"

#include "istream.h"
#include "streambuf.h"


// Implementation of ExtractIntegralCommand

ExtractIntegralCommand::ExtractIntegralCommand(basic_istream_char& is, bool pointer, bool defer)
  : pointer_(pointer),
    n_(0),
    neg_(false)
  {
    if(!defer)
      execute_template(is);
  }

ExtractIntegralCommand::~ExtractIntegralCommand()
  {}

ios::iostate ExtractIntegralCommand::execute(basic_istream_char& is)
  {
    ios::iostate state = ios::failbit;

    basic_streambuf_char* sb = is.rdbuf();

    int c = sb->sgetc();

    if(!pointer_ && (c == '+' || c == '-'))
    {
      neg_ = (c == '-');
      c = sb->snextc();
    }

    int base = 10;
    ios::fmtflags flags = is.flags();

    if((flags&ios::basefield) == ios::hex || pointer_)
      base = 16;
    else if((flags&ios::basefield) == ios::oct)
      base = 8;
    else if((flags&ios::basefield) == 0)
    {
      if(c == '0')
      {
        c = sb->snextc();

        if(c == 'x' || c == 'X')
        {
          base = 16;
          c = sb->snextc();
        }
        else
        {
          base = 8;
          state &= ~ios::failbit;
        }
      }
    }

    if(base == 10)
    {
      if(c >= '0' && c <= '9')
      {
        state &= ~ios::failbit;

        do
        {
          n_ = (n_*10)+(c-'0');
          c = sb->snextc();
        }
        while(c >= '0' && c <= '9');
      }
    }
    else if(base == 16)
    {
      if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
      {
        state &= ~ios::failbit;

        do
        {
          n_ = (n_*16)+(c <= '9' ? c-'0' : (c <= 'F' ? 10+c-'A' : 10+c-'a'));
          c = sb->snextc();
        }
        while((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'));
      }
    }
    else if(base == 8)
    {
      if(c >= '0' && c <= '7')
      {
        state &= ~ios::failbit;

        do
        {
          n_ = (n_*8)+(c-'0');
          c = sb->snextc();
        }
        while(c >= '0' && c <= '7');
      }
    }

    if(c == basic_istream_char::traits::eof())
      state |= ios::eofbit;

    return state;
  }


// Implementation of basic_istream_char

basic_istream_char& basic_istream_char::operator>>(short& n)
  {
    ExtractIntegralCommand cmd(*this);
    if(!fail())
      n = short(cmd.as_signed());
    return *this;
  }

basic_istream_char& basic_istream_char::operator>>(unsigned short& n)
  {
    ExtractIntegralCommand cmd(*this);
    if(!fail())
      n = (unsigned short)(cmd.as_unsigned());
    return *this;
  }

basic_istream_char& basic_istream_char::operator>>(int& n)
  {
    ExtractIntegralCommand cmd(*this);
    if(!fail())
      n = int(cmd.as_signed());
    return *this;
  }

basic_istream_char& basic_istream_char::operator>>(unsigned int& n)
  {
    ExtractIntegralCommand cmd(*this);
    if(!fail())
      n = (unsigned int)(cmd.as_unsigned());
    return *this;
  }

basic_istream_char& basic_istream_char::operator>>(long& n)
  {
    ExtractIntegralCommand cmd(*this);
    if(!fail())
      n = cmd.as_signed();
    return *this;
  }

basic_istream_char& basic_istream_char::operator>>(unsigned long& n)
  {
    ExtractIntegralCommand cmd(*this);
    if(!fail())
      n = cmd.as_unsigned();
    return *this;
  }

basic_istream_char& basic_istream_char::operator>>(void*& p)
  {
    ExtractIntegralCommand cmd(*this, true);
    if(!fail())
      p = cmd.as_pointer();
    return *this;
  }
